-------------Gruds in Space------------
A 4am crack                  2020-01-29
---------------------------------------

Name: Gruds in Space
Genre: adventure
Year: 1983
Credits: Chuck Sommerville, Joseph
  Dudar
Publisher: Sirius Software
Platform: Apple ][ (48K)
Media: 5.25-inch disk
Sides: 2
OS: custom

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  reads a few tracks then hangs

Copy ][+ nibble editor
  everything is non-standard

Disk Fixer
  nothing is readable except the
  boot sector, which is custom code

Why didn't COPYA or FDB work?
  not a 16-sector disk

Why didn't my EDD copy work?
  not clear yet

Next steps:

  1. Trace the boot
  2. ???
  3. Declare victory (*)

(*) go to the gym

                   ~

               Chapter 1
    In Which Everything Is Terrible


This story begins, as many stories do,
by copying the drive firmware to a
lower memory address so we can modify
it for our own nefarious purposes.
(Why, what kind of stories do *you*
read?)

*9600<C600.C6FFM
*96F8:4C 59 FF
*9600G
...reboots slot 6...
<beep>

Now we can look at the boot sector.
$800 is #$01, so it's only loading this
one sector and passing off control.

*801L

; show the hi-res page (uninitialized)
0801-   AD 50 C0    LDA   $C050
0804-   AD 52 C0    LDA   $C052
0807-   AD 54 C0    LDA   $C054
080A-   AD 57 C0    LDA   $C057

; set some vectors
080D-   A9 08       LDA   #$08
080F-   8D F3 03    STA   $03F3
0812-   8D F1 03    STA   $03F1
0815-   49 A5       EOR   #$A5
0817-   8D F4 03    STA   $03F4
081A-   A9 D0       LDA   #$D0
081C-   8D F2 03    STA   $03F2
081F-   8D F0 03    STA   $03F0
0822-   A0 00       LDY   #$00
0824-   8A          TXA
0825-   85 05       STA   $05
0827-   4A          LSR
0828-   4A          LSR
0829-   4A          LSR
082A-   4A          LSR
082B-   09 C0       ORA   #$C0
082D-   8D FD 08    STA   $08FD

; wipe memory $0900+
0830-   84 06       STY   $06
0832-   A9 09       LDA   #$09
0834-   85 07       STA   $07
0836-   85 02       STA   $02
0838-   A9 A0       LDA   #$A0
083A-   91 06       STA   ($06),Y   <--

; Make sure it actually worked, because
; apparently "storing values in memory"
; is a thing that sometimes doesn't
; work? Paranoid much? Oh wait, I'm
; about to make that not work. OK fair.
083C-   D1 06       CMP   ($06),Y

; If "storing values in memory" didn't
; work, immediately give up.
083E-   F0 03       BEQ   $0843
0840-   4C D0 08    JMP   $08D0     <--
0843-   C8          INY
0844-   D0 F2       BNE   $0838
0846-   E6 07       INC   $07
0848-   A5 07       LDA   $07
084A-   C9 C0       CMP   #$C0
084C-   90 EA       BCC   $0838

; Store #$00 in $200. (It's a surprise
; tool that will f*ck us later.)

; also wipe the language card, because
; hackers live there
084E-   8C 00 02    STY   $0200
0851-   A9 D0       LDA   #$D0
0853-   85 07       STA   $07
0855-   A2 30       LDX   #$30
0857-   AD 81 C0    LDA   $C081
085A-   AD 81 C0    LDA   $C081
085D-   B1 06       LDA   ($06),Y
085F-   91 06       STA   ($06),Y
0861-   C8          INY
0862-   D0 F9       BNE   $085D
0864-   E6 07       INC   $07
0866-   CA          DEX
0867-   D0 F4       BNE   $085D

; OK here we go with actually doing
; something useful
0869-   A6 05       LDX   $05
086B-   A9 68       LDA   #$68
086D-   85 07       STA   $07
086F-   A9 04       LDA   #$04
0871-   85 01       STA   $01
0873-   A0 00       LDY   #$00

; custom nibble prologue ($AD $DA $DD)
0875-   BD 8C C0    LDA   $C08C,X
0878-   10 FB       BPL   $0875
087A-   C9 AD       CMP   #$AD
087C-   D0 F7       BNE   $0875
087E-   BD 8C C0    LDA   $C08C,X
0881-   10 FB       BPL   $087E
0883-   C9 DA       CMP   #$DA
0885-   D0 F3       BNE   $087A
0887-   BD 8C C0    LDA   $C08C,X
088A-   10 FB       BPL   $0887
088C-   C9 DD       CMP   #$DD
088E-   D0 EA       BNE   $087A
0890-   84 00       STY   $00

; read 4-and-4-encoded data
0892-   BD 8C C0    LDA   $C08C,X
0895-   10 FB       BPL   $0892
0897-   38          SEC
0898-   2A          ROL
0899-   85 04       STA   $04
089B-   B0 12       BCS   $08AF
089D-   BD 8C C0    LDA   $C08C,X
08A0-   10 FB       BPL   $089D
08A2-   38          SEC
08A3-   2A          ROL

; but store it in the same address over
; and over(?!?)
08A4-   85 04       STA   $04
08A6-   C8          INY
08A7-   D0 06       BNE   $08AF

; ($06) -> $6800 which is the target
; memory address
08A9-   E6 07       INC   $07

; $01 is #$04 (initialized at $0871)
; which is probably a sector count
08AB-   C6 01       DEC   $01
08AD-   F0 0F       BEQ   $08BE

; read actual data
08AF-   BD 8C C0    LDA   $C08C,X
08B2-   10 FB       BPL   $08AF

; ANDed with the last 4-and-4-encoded
; value we read earlier(?!?)
08B4-   25 04       AND   $04
08B6-   91 06       STA   ($06),Y

; and keep a rolling checksum
08B8-   45 00       EOR   $00
08BA-   85 00       STA   $00

; loop back to read more
08BC-   B0 DF       BCS   $089D

; one-nibble epilogue is just the
; checksum
08BE-   BD 8C C0    LDA   $C08C,X
08C1-   10 FB       BPL   $08BE
08C3-   25 04       AND   $04

; if checksum doesn't match, try again
08C5-   45 00       EOR   $00
08C7-   D0 03       BNE   $08CC

; jump to the code we just read
08C9-   4C 00 68    JMP   $6800

; try again after read error
08CC-   C6 02       DEC   $02
08CE-   D0 9B       BNE   $086B

; The Badlands --
; clear screen, print "BOOT ERROR",
; play a cute sound, and reboot
08D0-   20 58 FC    JSR   $FC58
08D3-   A0 00       LDY   #$00
08D5-   B9 E0 08    LDA   $08E0,Y
08D8-   F0 11       BEQ   $08EB
08DA-   99 00 04    STA   $0400,Y
08DD-   C8          INY
08DE-   D0 F5       BNE   $08D5
08E0-   "BOOT ERROR"
08EA-   00          BRK
08EB-   AD 51 C0    LDA   $C051
08EE-   A0 80       LDY   #$80
08F0-   A9 1A       LDA   #$1A
08F2-   20 A8 FC    JSR   $FCA8
08F5-   AD 30 C0    LDA   $C030
08F8-   88          DEY
08F9-   D0 F5       BNE   $08F0
08FB-   4C 00 C6    JMP   $C600

If all goes well, we read 4 sectors of
data into $6800-$6BFF and jump to
$6800.

If all goes poorly, well... it's off
to The Badlands with you!

                   ~

               Chapter 2
        In Which All Goes Well,
          For The Time Being


To capture the code at $6800, I can
trace the boot and interrupt it at
$08C9 where it would ordinarily jump
to $6800.

*96F8L

; disable memory wipe (not strictly
; necessary since I don't need to
; persist in memory, but it offends me)
96F8-   A9 24       LDA   #$24
96FA-   8D 3A 08    STA   $083A

; disable CMP to ensure the memory wipe
; worked, since, you know, it didn't
96FD-   A9 2C       LDA   #$2C
96FF-   8D 40 08    STA   $0840

; reboot to my work disk instead of
; continuing to the next phase of the
; boot
9702-   A9 00       LDA   #$00
9704-   8D CA 08    STA   $08CA
9707-   A9 C5       LDA   #$C5
9709-   8D CB 08    STA   $08CB

; start the boot
970C-   4C 01 08    JMP   $0801

*BSAVE TRACE1,A$9600,L$10F
*9600G
...reboots slot 6...
...read read read...
...reboots slot 5...

*BSAVE OBJ.6800-6BFF,A$6800,L$400
*6800L

; not sure what this is about, but it's
; writing a JMP instruction at a
; previously uninitialized address
6800-   A9 8F       LDA   #$8F
6802-   8D 01 67    STA   $6701
6805-   A9 69       LDA   #$69
6807-   8D 02 67    STA   $6702
680A-   A9 4C       LDA   #$4C
680C-   8D 00 67    STA   $6700

680F-   A5 05       LDA   $05
6811-   8D D7 6B    STA   $6BD7
6814-   8D 03 67    STA   $6703
6817-   4A          LSR
6818-   4A          LSR
6819-   4A          LSR
681A-   4A          LSR
681B-   09 C0       ORA   #$C0
681D-   8D CA 6B    STA   $6BCA

; This was set to 0 at $084E. If
; someone were trying to interrupt the
; boot and manually run this part,
; their typed monitor command would be
; stored at $200, overwriting the 0
; value stored there by the previous
; phase of the bootloader.
6820-   AD 00 02    LDA   $0200
6823-   F0 03       BEQ   $6828

; off to The Badlands with you!
6825-   4C 76 6B    JMP   $6B76

; otherwise, execution continues here
6828-   A9 00       LDA   #$00
682A-   8D DE 6B    STA   $6BDE

; set all the vectors (even more this
; time)
682D-   A9 76       LDA   #$76
682F-   8D F0 03    STA   $03F0
6832-   8D F2 03    STA   $03F2
6835-   8D F6 03    STA   $03F6
6838-   8D F9 03    STA   $03F9
683B-   8D FC 03    STA   $03FC
683E-   8D FE 03    STA   $03FE
6841-   8D FA FF    STA   $FFFA
6844-   8D FC FF    STA   $FFFC
6847-   8D FE FF    STA   $FFFE
684A-   A9 6B       LDA   #$6B
684C-   8D F1 03    STA   $03F1
684F-   8D F3 03    STA   $03F3
6852-   8D F7 03    STA   $03F7
6855-   8D FA 03    STA   $03FA
6858-   8D FD 03    STA   $03FD
685B-   8D FF 03    STA   $03FF
685E-   8D FB FF    STA   $FFFB
6861-   8D FD FF    STA   $FFFD
6864-   8D FF FF    STA   $FFFF
6867-   49 A5       EOR   #$A5
6869-   8D F4 03    STA   $03F4
686C-   AD 80 C0    LDA   $C080

; setting up for... something
686F-   A9 05       LDA   #$05
6871-   8D E9 6B    STA   $6BE9
6874-   8D EA 6B    STA   $6BEA
6877-   8D EB 6B    STA   $6BEB
687A-   A9 02       LDA   #$02
687C-   8D E0 6B    STA   $6BE0
687F-   4A          LSR
6880-   A8          TAY
6881-   B9 FB 68    LDA   $68FB,Y
6884-   85 D3       STA   $D3
6886-   A9 00       LDA   #$00
6888-   85 D2       STA   $D2

*68FB.

68FB- .. .. .. 00 08 14 40 4C
6900- 58 5A 7C 88 94 A0 AC B4

Those look suspiciously like a set of
memory addresses (high bytes, at least)
into which we'll be reading data from
disk. It's 1-indexed;; A starts at
#$02, but the LSR makes it #$01. So we
skip the #$00 at $68FB, and the first
address in ($D2) is $0800.

688A-   AD E0 6B    LDA   $6BE0
688D-   AE D7 6B    LDX   $6BD7

; move to track (not shown)
6890-   20 B5 6A    JSR   $6AB5

; wait routine, like $FCA8 (not shown)
6893-   A9 64       LDA   #$64
6895-   20 CB 6B    JSR   $6BCB

; probably a sector count
6898-   A9 0C       LDA   #$0C
689A-   8D E1 6B    STA   $6BE1

; almost certainly the "read a track"
; routine
689D-   20 16 6A    JSR   $6A16

*6A16L

6A16-   AE D7 6B    LDX   $6BD7
6A19-   A0 00       LDY   #$00
6A1B-   A9 06       LDA   #$06
6A1D-   8D DF 6B    STA   $6BDF
6A20-   A5 D3       LDA   $D3
6A22-   8D EC 6B    STA   $6BEC
6A25-   AD E1 6B    LDA   $6BE1
6A28-   8D E7 6B    STA   $6BE7
6A2B-   AD EC 6B    LDA   $6BEC
6A2E-   85 D3       STA   $D3

; find a custom prologue ($AD $DA $DD)
6A30-   BD 8C C0    LDA   $C08C,X
6A33-   10 FB       BPL   $6A30
6A35-   C9 AD       CMP   #$AD
6A37-   D0 F7       BNE   $6A30
6A39-   BD 8C C0    LDA   $C08C,X
6A3C-   10 FB       BPL   $6A39
6A3E-   C9 DA       CMP   #$DA
6A40-   D0 F3       BNE   $6A35
6A42-   BD 8C C0    LDA   $C08C,X
6A45-   10 FB       BPL   $6A42
6A47-   C9 DD       CMP   #$DD
6A49-   D0 EA       BNE   $6A35
6A4B-   8C E6 6B    STY   $6BE6

; read 4-and-4-encoded data
6A4E-   BD 8C C0    LDA   $C08C,X
6A51-   10 FB       BPL   $6A4E
6A53-   38          SEC
6A54-   2A          ROL
6A55-   8D E8 6B    STA   $6BE8
6A58-   B0 14       BCS   $6A6E
6A5A-   BD 8C C0    LDA   $C08C,X
6A5D-   10 FB       BPL   $6A5A
6A5F-   38          SEC
6A60-   2A          ROL

; but store it in the same address over
; and over(?!?) (just like the initial
; bootloader)
6A61-   8D E8 6B    STA   $6BE8
6A64-   C8          INY
6A65-   D0 07       BNE   $6A6E

; increment target address
6A67-   E6 D3       INC   $D3

; decrement sector count
6A69-   CE E7 6B    DEC   $6BE7
6A6C-   F0 12       BEQ   $6A80

; now actually read the sector data
6A6E-   BD 8C C0    LDA   $C08C,X
6A71-   10 FB       BPL   $6A6E

; ANDed with the last 4-and-4-encoded
; value we read earlier(?!?)
6A73-   2D E8 6B    AND   $6BE8
6A76-   91 D2       STA   ($D2),Y

; and keep a rolling checksum
6A78-   4D E6 6B    EOR   $6BE6
6A7B-   8D E6 6B    STA   $6BE6

; loop back to read more
6A7E-   B0 DA       BCS   $6A5A

; one-nibble epilogue is just the
; checksum
6A80-   BD 8C C0    LDA   $C08C,X
6A83-   10 FB       BPL   $6A80
6A85-   2D E8 6B    AND   $6BE8
6A88-   4D E6 6B    EOR   $6BE6

; if checksum doesn't match, try again
6A8B-   D0 02       BNE   $6A8F

; all done (whew)
6A8D-   18          CLC
6A8E-   60          RTS

; if the checksum didn't match, we
; recalibrate by seeking to track 0 and
; back to the current track (like DOS,
; more or less) (not shown)
6A8F-   20 99 6A    JSR   $6A99

; decrement Death Counter (initialized
; as 6 at $6A1D)
6A92-   CE DF 6B    DEC   $6BDF
6A95-   D0 8E       BNE   $6A25

; couldn't read 6 times, give up and
; return an error flag to the caller
6A97-   38          SEC
6A98-   60          RTS

Continuing from $68A0...

68A0-   90 03       BCC   $68A5

; if read failed, off to The Badlands!
68A2-   4C 53 6B    JMP   $6B53

; otherwise increment phase in
; preparation for reading the next
; track
68A5-   EE E0 6B    INC   $6BE0
68A8-   EE E0 6B    INC   $6BE0

; loop-and-read-again, up to track $0D
68AB-   AD E0 6B    LDA   $6BE0
68AE-   C9 1A       CMP   #$1A
68B0-   90 CD       BCC   $687F

This loop reads data from tracks $01-
$0C into $0800-$BFFF, skipping hi-res
page 1 which is displayed throughout.

And then the real fun(*) begins.

(*) not guaranteed, actual fun may vary

                   ~

               Chapter 3
   Can Only You See The Time Being?


After the game code has been read, we
are on track $0C. But we're not done.
Oh, no.

; move the head to track $0D
68B2-   A9 1A       LDA   #$1A
68B4-   8D E0 6B    STA   $6BE0
68B7-   20 B5 6A    JSR   $6AB5

; and wait
68BA-   A9 FF       LDA   #$FF
68BC-   20 CB 6B    JSR   $6BCB

; and now this
68BF-   20 08 69    JSR   $6908

*6908L

6908-   AE D7 6B    LDX   $6BD7
690B-   A9 00       LDA   #$00
690D-   8D D9 6B    STA   $6BD9
6910-   8D D8 6B    STA   $6BD8
6913-   A0 32       LDY   #$32
6915-   BD 8E C0    LDA   $C08E,X
6918-   BD 8C C0    LDA   $C08C,X
691B-   10 FB       BPL   $6918
691D-   88          DEY
691E-   D0 F8       BNE   $6918

; loop forever until we find $DD nibble
6920-   BD 8C C0    LDA   $C08C,X
6923-   10 FB       BPL   $6920
6925-   C9 DD       CMP   #$DD
6927-   D0 F7       BNE   $6920

; skip several nibbles
6929-   BD 8C C0    LDA   $C08C,X
692C-   10 FB       BPL   $6929
692E-   BD 8C C0    LDA   $C08C,X
6931-   10 FB       BPL   $692E
6933-   BD 8C C0    LDA   $C08C,X
6936-   10 FB       BPL   $6933
6938-   BD 8C C0    LDA   $C08C,X
693B-   10 FB       BPL   $6938
693D-   BD 8C C0    LDA   $C08C,X
6940-   10 FB       BPL   $693D
6942-   BD 8C C0    LDA   $C08C,X
6945-   10 FB       BPL   $6942
6947-   BD 8C C0    LDA   $C08C,X
694A-   10 FB       BPL   $6947
694C-   BD 8C C0    LDA   $C08C,X
694F-   10 FB       BPL   $694C

; look for another $DD nibble
6951-   BD 8C C0    LDA   $C08C,X
6954-   10 FB       BPL   $6951
6956-   C9 DD       CMP   #$DD
6958-   F0 0A       BEQ   $6964

; count exactly how long it takes to
; find the second $DD nibble
695A-   EE D9 6B    INC   $6BD9
695D-   D0 F2       BNE   $6951
695F-   EE D8 6B    INC   $6BD8
6962-   D0 ED       BNE   $6951

; read two 4-and-4-encoded values and
; store them in $6BDD and $6BDC
6964-   BD 8C C0    LDA   $C08C,X
6967-   10 FB       BPL   $6964
6969-   38          SEC
696A-   2A          ROL
696B-   8D E8 6B    STA   $6BE8
696E-   BD 8C C0    LDA   $C08C,X
6971-   10 FB       BPL   $696E
6973-   2D E8 6B    AND   $6BE8
6976-   8D DD 6B    STA   $6BDD     <--
6979-   BD 8C C0    LDA   $C08C,X
697C-   10 FB       BPL   $6979
697E-   38          SEC
697F-   2A          ROL
6980-   8D E8 6B    STA   $6BE8
6983-   BD 8C C0    LDA   $C08C,X
6986-   10 FB       BPL   $6983
6988-   2D E8 6B    AND   $6BE8
698B-   8D DC 6B    STA   $6BDC     <--
698E-   60          RTS

Is that all? Well yes, but actually no.
Looking at that track in the Copy ][+
nibble editor, it is almost entirely
$FF nibbles. In fact, there is only one
$DD nibble on the entire track, which
means that this "nibble count" routine
is actually a "track length" routine.

Continuing from $68C2...

68C2-   20 C1 69    JSR   $69C1

*69C1L

; check phase, which at this point is
; still $1A
69C1-   AD E0 6B    LDA   $6BE0
69C4-   C9 1A       CMP   #$1A
69C6-   F0 1A       BEQ   $69E2
...
69E2-   18          CLC
69E3-   AD DD 6B    LDA   $6BDD
69E6-   8D DB 6B    STA   $6BDB
69E9-   AD DC 6B    LDA   $6BDC
69EC-   8D DA 6B    STA   $6BDA
69EF-   60          RTS

So far, all we've done is count the
nibbles on track $0D, then moved the
post-nibble-stream epilogue values from
one address to another.

Continuing from $68C5...

; this will branch, because we cleared
; the carry at $69E2
68C5-   90 03       BCC   $68CA

; no Badlands for us (this time)
68C7-   4C 5E 6B    JMP   $6B5E

; now increment the phase again, to
; track $0E
68CA-   EE E0 6B    INC   $6BE0
68CD-   EE E0 6B    INC   $6BE0

68D0-   AD E0 6B    LDA   $6BE0
68D3-   C9 1E       CMP   #$1E

; not done yet, so we don't branch here
68D5-   B0 10       BCS   $68E7

; seek to track $0E
68D7-   20 B5 6A    JSR   $6AB5

; wait
68DA-   A9 FF       LDA   #$FF
68DC-   20 CB 6B    JSR   $6BCB
68DF-   A9 0A       LDA   #$0A
68E1-   8D EA 6B    STA   $6BEA

; now loop back
68E4-   4C BF 68    JMP   $68BF

$68BF, of course, looks like this:

68BF-   20 08 69    JSR   $6908

So we're doing the nibble count (a.k.a.
track length) routine again, but on
track $0E instead of track $0D. But the
second time around, we'll call $69C1
(from $68C2) and take a different path.

; check phase, which is now $1C
69C1-   AD E0 6B    LDA   $6BE0
69C4-   C9 1A       CMP   #$1A

; no branch this time
69C6-   F0 1A       BEQ   $69E2

; do several things, any one of which
; can lead us to the success path
; ($69E2, which clears the carry that
; the caller checks)
69C8-   20 F0 69    JSR   $69F0
69CB-   20 07 6A    JSR   $6A07
69CE-   F0 12       BEQ   $69E2     <--
69D0-   20 F9 69    JSR   $69F9
69D3-   20 07 6A    JSR   $6A07
69D6-   F0 0A       BEQ   $69E2     <--
69D8-   20 F9 69    JSR   $69F9
69DB-   20 07 6A    JSR   $6A07
69DE-   F0 02       BEQ   $69E2     <--

; failure path sets the carry, and the
; caller will jump to The Badlands
69E0-   38          SEC
69E1-   60          RTS

So what's at $69F0, $6A07, and $69F9?

*69F0L

; increment the (2-byte) nibble count
; that was calculated inside the
; subroutine at $6908
69F0-   EE D9 6B    INC   $6BD9
69F3-   D0 03       BNE   $69F8
69F5-   EE D8 6B    INC   $6BD8
69F8-   60          RTS

; decrement the (2-byte) nibble count
69F9-   CE D9 6B    DEC   $6BD9
69FC-   AD D9 6B    LDA   $6BD9
69FF-   C9 FF       CMP   #$FF
6A01-   D0 03       BNE   $6A06
6A03-   CE D8 6B    DEC   $6BD8
6A06-   60          RTS

; validate the nibble count against the
; epilogue values we copied earlier
6A07-   AD D9 6B    LDA   $6BD9
6A0A-   CD DB 6B    CMP   $6BDB
6A0D-   D0 06       BNE   $6A15
6A0F-   AD D8 6B    LDA   $6BD8
6A12-   CD DA 6B    CMP   $6BDA
6A15-   60          RTS

So track $0D and $0E are both checked,
their track lengths need to match
(within 1 nibble), and track $0D
contains the answer to the question
"how long is track $0E?"

Delightful.

And that really is it, because the next
time we double-increment the phase (at
$68CA), it becomes $1E and we branch
out of this loop:

68CA-   EE E0 6B    INC   $6BE0
68CD-   EE E0 6B    INC   $6BE0
68D0-   AD E0 6B    LDA   $6BE0
68D3-   C9 1E       CMP   #$1E
68D5-   B0 10       BCS   $68E7  ; yes!
...

; turn off drive motor
68E7-   BD 88 C0    LDA   $C088,X

; set some magic values in zero page
68EA-   A9 00       LDA   #$00
68EC-   85 20       STA   $20
68EE-   85 22       STA   $22
68F0-   A9 80       LDA   #$80
68F2-   85 23       STA   $23
68F4-   A9 BD       LDA   #$BD
68F6-   85 21       STA   $21

; start the game
68F8-   4C 00 08    JMP   $0800

The first thing the game does is ask
you to put in side 2 (technically "a
copy" of side 2), which is unprotected.
The protected side 1 is a single
loader, and we've traced it completely.

Let's capture it.

                   ~

               Chapter 4
   Oh Yeah, It's All Coming Together


*9600<C600.C6FFM

; (same as previous trace)
96F8-   A9 24       LDA   #$24
96FA-   8D 3A 08    STA   $083A
96FD-   A9 2C       LDA   #$2C
96FF-   8D 40 08    STA   $0840
9702-   A9 0F       LDA   #$0F
9704-   8D CA 08    STA   $08CA
9707-   A9 97       LDA   #$97
9709-   8D CB 08    STA   $08CB

; start the boot
970C-   4C 01 08    JMP   $0801

; break to monitor instead of jumping
; to game entry point
970F-   A9 59       LDA   #$59
9711-   8D F9 68    STA   $68F9
9714-   A9 FF       LDA   #$FF
9716-   8D FA 68    STA   $68FA

; continue the boot
9719-   4C 00 68    JMP   $6800

*BSAVE TRACE2,A$9600,L$11C

*9600G
...reboots slot 6...
...read read read...
<beep>

My work disk will overwrite $800-$8FF
and $BF00-$BFFF. Everything else is
loaded directly into the language
card, which is nice. Hi-res page 1
is wiped and never loaded, so let's
copy some pages there.

*2800<800.8FFM
*3800<B800.BFFFM

; reboot to my work disk
*C500G
...

]BSAVE OBJ.B800-BFFF,A$3800,L$800
]CALL -151

; restore page 8
*800<2800.28FFM

; re-clear hi-res page 1
*2000:A0 N 2001<2000.3FFEM

; restore jump to game entry point
*68F8:4C 00 08

*BSAVE OBJ.0800-B7FF,A$800,L$B000

That's the whole side 1.

Fun fact: since side 2 is unprotected,
$B800-$BFFF is just the standard RWTS
of DOS 3.3.

My plan is to write the game code to a
new disk on tracks 1+, have the disk
load the standard DOS 3.3 RWTS ($B600+)
from track 0, and use that RWTS to read
tracks 1+ into $0800-$B5FF. Then I can
jump to $68EA, which will set the magic
values in zero page and jump to the
game entry point at $0800.

Easy peasy.

A quick write-game-to-disk program:

; page count (decremented)
0300-   A9 B0       LDA   #$B0
0302-   85 FF       STA   $FF

; logical sector (incremented)
0304-   A9 00       LDA   #$00
0306-   85 FE       STA   $FE

; call RWTS to write sector
0308-   A9 03       LDA   #$03
030A-   A0 88       LDY   #$88
030C-   20 D9 03    JSR   $03D9

; increment logical sector, wrap around
; from $0F to $00 and increment track
030F-   E6 FE       INC   $FE
0311-   A4 FE       LDY   $FE
0313-   C0 10       CPY   #$10
0315-   D0 07       BNE   $031E
0317-   A0 00       LDY   #$00
0319-   84 FE       STY   $FE
031B-   EE 8C 03    INC   $038C

; (I've reused this writer program to
; write disks that need a logical-to-
; physical sector mapping, which would
; appear here. This disk doesn't need
; to do that. Game code will be stored
; on logical sectors in increasing
; order, like a regular DOS disk.)
031E-   EA EA EA
0321-   8C 8D 03    STY   $038D

; increment page to write
0324-   EE 91 03    INC   $0391

; loop until done with all pages
0327-   C6 FF       DEC   $FF
0329-   D0 DD       BNE   $0308
032B-   60          RTS

*388.397

; RWTS parameter table, pre-initialized
; with slot 6, drive 1, track $01,
; sector $00, address $0800, and RWTS
; write command ($02)
0388- 01 60 01 00 01 00 FB F7
0390- 00 08 00 00 02 00 00 60

*BSAVE MAKE,A$300,L$98

[S6,D1=freshly formatted DOS 3.3 disk]

*300G

Boom. I have the entire game on tracks
$01-$0B of a standard 16-sector disk,
and a standard DOS 3.3 RWTS on track 0.

Finally, I can tweak the DOS bootloader
code at $B700 to read the entire game
code into memory with one call.

                 --v--

T00,S01
----------- DISASSEMBLY MODE ----------
0000:8E E9 B7       STX   $B7E9
0003:8E F7 B7       STX   $B7F7
0006:A9 01          LDA   #$01
0008:8D F8 B7       STA   $B7F8
000B:8D EA B7       STA   $B7EA

; contains #$AE (total sector count)
000E:AD E0 B7       LDA   $B7E0
0011:8D E1 B7       STA   $B7E1

; start on track $0B
0014:A9 0B          LDA   #$0B
0016:8D EC B7       STA   $B7EC

; start on sector $0D
0019:A9 0D          LDA   #$0D
001B:8D ED B7       STA   $B7ED

; contains #$B6 (so T0B,S0D is read
; into $B500)
001E:AC E7 B7       LDY   $B7E7
0021:88             DEY
0022:8C F1 B7       STY   $B7F1
0025:A9 01          LDA   #$01
0027:8D F4 B7       STA   $B7F4
002A:8A             TXA
002B:4A             LSR
002C:4A             LSR
002D:4A             LSR
002E:4A             LSR
002F:AA             TAX
002F:AA             TAX
0030:A9 00          LDA   #$00
0032:9D F8 04       STA   $04F8,X
0035:9D 78 04       STA   $0478,X

; read it all in one shot
0038:20 93 B7       JSR   $B793

; jump into game's original bootloader
; to set magic zero page values and
; start the game
003B:4C EA 68       JMP   $68EA

                 --^--

]PR#6
...boots, loads, displays title screen,
asks for side 2, which loads and works
and is glorious...

Quod erat liberandum.

---------------------------------------
A 4am crack                    No. 2146
------------------EOF------------------
